package cn.blnp.net.flowable.task.service.introduce;

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

/**
 * <h3>服务任务，基本介绍</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/12 16:42
 */
@Slf4j
@SpringBootTest
public class ServiceTaskTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    
    /**
     *  <p>
     *      服务任务不同于用户任务，用户任务需要人工处理，而服务任务是一种自动化任务。在Flowable中，当流程流转到服务任务时，会自动执行服务任务中编写的Java程序。Java程序执行完毕后，
     *   流程将沿服务任务的外出顺序流继续流转。服务任务由serviceTask元素定义。Flowable提供了3种方法来声明Java调用逻辑，用于指定该服务任务所要调用的Java类或Spring容器的Bean.
     *  </p>
     *  <h2>通过flowable:class属性指定一个Java类</h2>
     *  <hr/>
     *  <p>
     *      通过这种方式指定一个在流程流转到服务任务时所要调用的Java类，需要在serviceTask的flowable:class属性中指定合法的全路径类名，该类必须实现JavaDelegate、FlowableBehavior 或
     *   FutureJavaDelegate接口。
     *      <ul>
     *          <li>
     *              若指定为实现JavaDelegate接口的Java类，则示例代码如下：<br/>
     *              {@code
     *                  <serviceTask id="serviceTask1" name="服务任务" flowable:class="com.bpm.example.servicetask.demo1.delegate.MyJavaDelegate" />
     *              }
     *<pre>
     *    {@code
     *        public class MyJavaDelegate implements JavaDelegate {
     *            @Override
     *            public void execute(DelegateExecution execution) {
     *                //在这里编写服务任务调用逻辑
     *            }
     *        }
     *    }
     *</pre>
     *          </li>
     *          <li>
     *              若指定为实现ActivityBehavior接口的Java类，则示例代码如下：<br/>
     *              {@code
     *                  <serviceTask id="serviceTask2" name="服务任务" flowable:class="com.bpm.example.servicetask.demo1.behavior.MyActivityBehavior" />
     *              }
     *<pre>
     *     {@code
     *          public class MyActivityBehavior implements ActivityBehavior {
     *              @Override
     *              public void execute(DelegateExecution execution) {
     *                  //在这里编写服务任务调用逻辑
     *              }
     *          }
     *     }
     *</pre>
     *          </li>
     *      </ul>
     *  </p>
     *  <p>
     *      这里需要<b style="color:red;">注意的一个误区</b>是，前面介绍的两种方式，服务任务的执行都是单线程的。这些服务任务并不是并行执行，而是按顺序一个接一个串行同步执行的。如若需要并行异步执行，
     *  则实现FutureJavaDelegate接口。FutureJavaDelegate继承自JavaDelegate接口，并添加了返回Future的方法execute()和处理返回结果的afterExecution()方法。指定为实现FutureJavaDelegate接口的
     *  Java类的示例代码如下：<br/>
     *  {@code
     *      <serviceTask id="serviceTask3" name="服务任务" flowable:class="cn.blnp.net.flowable.task.service.MyFutureJavaDelegate" />
     *  }<br/>
     *  详见：{@link MyFutureJavaDelegate}
     *  </p>
     *  <p>
     *      FutureJavaDelegate类还有两个子接口FlowableFutureJavaDelegate和MapBasedFlowableFutureJavaDelegate，它们同样能使服务任务并行异步执行。
     *      <ol>
     *          <li>
     *              FlowableFutureJavaDelegate 接口案例：{@link MyFlowableFutureJavaDelegate}
     *          </li>
     *          <li>
     *              MapBasedFlowableFutureJavaDelegate 接口案例：{@link MyMapBasedFlowableFutureJavaDelegate}
     *          </li>
     *      </ol>
     *  </p>
     *  <p>
     *      <b style="color:#000000;">重点强调：</b>流程定义中由服务任务使用flowable:class属性指定的Java类不会在流程部署时实例化。服务任务通过flowable:class属性指定的Java类
     *  只会创建一个实例，即只有当流程初次流转到调用该Java类的服务任务时，才会实例化一个对象，该对象会被复用。所有的流程实例都会共享相同的类实例，并调用其execute()方法。这就意味着，
     *  如果该Java类中使用了成员变量，必须保证线程安全（在多线程运行环境下，每次调用都能得到正确的逻辑结果）。这也会影响属性注入的处理方式。
     *  </p>
     **/
    @Test
    public void testClass() {
        
    }


    /**
     *  <h2>通过flowable:delegateExpression使用委托表达式指定</h2>
     *  <p>
     *      &emsp;&emsp;这种方式可以通过flowable:delegateExpression属性指定为解析结果为对象的表达式，该对象必须遵循与使用flowable:class属性时创建的对象相同的规则：<br/>
     *      {@code
     *          <serviceTask id="serviceTask4" name="服务任务" flowable:delegateExpression="${delegateExpressionBean}" />
     *      }<br/>
     *      &emsp;&emsp;其中，delegateExpressionBean是一个实现JavaDelegate接口的Bean，在表达式调用之前需要初始化到流程变量中，或者注册在Spring容器中。委托表达式中只需指定Bean的名称，
     *  无须指定方法名，工作流引擎会自动调用其execute()方法。
     *  </p>
     **/
    @Test
    public void testExpression() {
        
    }

    /**
     *  <p>
     *      这种方式可以通过flowable:expression属性指定为UEL方法表达式或值表达式，调用一个普通Java Bean的方法或属性，在表达式调用之前需要将其初始化到流程变量中，或者注册在Spring容器中。
     *  与通过flowable:delegateExpression属性指定方式不同，通过flowable:expression属性指定的表达式调用的Bean<b>不需要实现JavaDelegate接口，表达式中必须指定调用的方法名或属性名。</b>
     *  <pre>
     *      {@code
     *          <serviceTask id="serviceTask5" name="服务任务" flowable:expression="${businessBean.calculateMount1()}" />
     *
     *          <serviceTask id="serviceTask6" name="服务任务" flowable:expression="${businessBean.calculateMount2(execution, money)}" />
     *
     *          <serviceTask id="serviceTask7" name="服务任务" flowable:expression="${businessBean.total}" />
     *      }
     *  </pre>
     *  BusinessBean 对象详见：{@link BusinessBean}
     *  </p>
     **/
    @Test
    public void testUel() {

    }
}
